﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace TiledPlatformer.Entity
{
    public class Player : MovableObject
    {
        float walkSpeed = 0.5f;
        float MAX_WALK_SPEED = 4;
        float MAX_FALL = 12;

        float jumpForce = -11f;
        float gravityForce = 0.5f;

        public enum State
        {
            STAND,
            LEFT,
            RIGHT,
        };

        bool isFalling;
        bool onGround;

        public bool cantMoveLeft;
        public bool cantMoveRight;

        public State currentState;

        PlayerIndex index;

        public Player(Vector2 position, Texture2D texture, PlayerIndex index)
            : base(position, texture)
        {
            this.index = index;
        }

        int groundY = 0;

        bool isOverLadder;
        public override void Update()
        {
            //TODO: Add player update logic
            currentState = State.STAND;
            isOverLadder = false;
            cantMoveRight = false;
            cantMoveLeft = false;

            handleCollision();
            handleInput();

            updateState();

            position.X += Velocity.X;
            position.Y += Velocity.Y;

            // Reset our falling state
            isFalling = true;

            //cantMoveLeft  = false;
            //cantMoveRight = false;

            base.Update();
        }

        private void handleInput()
        {
            KeyboardState keyState = Keyboard.GetState();

            if (keyState.IsKeyDown(Keys.A)) currentState = State.LEFT;
            if (keyState.IsKeyDown(Keys.D)) currentState = State.RIGHT;
            if (keyState.IsKeyDown(Keys.Space)) requestJump();
            if (keyState.IsKeyDown(Keys.W) && isOverLadder)
            {
                position.Y -= 2;
            }
        }

        //bool topIntersecting;
        float previousBottom;
        private void handleCollision()
        {
            foreach (GameObject o in Platformer.gameObjects)
            {
                if (collisionBox.Intersects(o.collisionBox))
                {
                    if (o is Ladder)
                    {
                        isOverLadder = true;
                    }
                }
                if (leftBox.Intersects(o.collisionBox) && o.type!=ObjectType.PASSTHRU)
                { 
                    cantMoveLeft = true;
                    //position.X += 2;
                }

                if (rightBox.Intersects(o.collisionBox) && o.type != ObjectType.PASSTHRU)
                { 
                    cantMoveRight = true;
                    //position.X -= 2;
                }

                if (topBox.Intersects(o.collisionBox) && o.type != ObjectType.PASSTHRU)
                    Velocity.Y = 1;

                if (bottomBox.Intersects(o.collisionBox))
                {
                    groundY = o.collisionBox.Y - collisionBox.Height;
                    Velocity.Y = 0;
                    isFalling = false;
                    onGround = true;
                }

                Vector2 depth = RectangleExtensions.GetIntersectionDepth(collisionBox, o.collisionBox);
                if (depth != Vector2.Zero && o.type != ObjectType.PASSTHRU)
                {
                    float absDepthX = Math.Abs(depth.X);
                    float absDepthY = Math.Abs(depth.Y);
                    if (absDepthY < absDepthX)
                    {
                        // If we crossed the top of a tile, we are on the ground.
                        if (previousBottom <= o.collisionBox.Top)
                            onGround = true;

                        // Ignore platforms, unless we are on the ground.
                        if (onGround)
                        {
                            // Resolve the collision along the Y axis.
                            position = new Vector2(position.X, position.Y + depth.Y);

                            // Perform further collisions with the new bounds.
                            //bounds = BoundingRectangle;
                        }
                    }
                    else // Ignore platforms.
                    {
                        // Resolve the collision along the X axis.
                        position = new Vector2(position.X + depth.X, position.Y);

                        // Perform further collisions with the new bounds.
                        //bounds = BoundingRectangle;
                    }
                }
            }
            previousBottom = collisionBox.Bottom;
        }

        private void updateState()
        {
            if (isOverLadder)
            {
                onGround = false;
                isFalling = false;
            }
            // Handle vertical movement
            if (onGround)
            {
                position.Y = groundY;
            }

            if (isFalling)
            {
                Velocity.Y = Math.Min(Velocity.Y + gravityForce, MAX_FALL);
                onGround = false;
            }

            // Handle horizontal movement
            if (currentState == State.LEFT)
            {
                Velocity.X = Math.Max(Velocity.X - walkSpeed, -MAX_WALK_SPEED);
            }
            if (currentState == State.RIGHT)
                Velocity.X = Math.Min(Velocity.X + walkSpeed, MAX_WALK_SPEED);
            if (currentState == State.STAND || (cantMoveLeft && currentState == State.LEFT) || (cantMoveRight && currentState == State.RIGHT))
                Velocity.X = 0;
        }

        private void requestJump()
        {
            if (!isFalling && onGround)
            {
                Velocity.Y = jumpForce;
            }
        }

        public override void Draw(SpriteBatch batch)
        {
            //TODO: Draw player

            base.Draw(batch);
        }
    }
}
